#include <stdio.h>
/*#define _POSIX_SOURCE*/
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
#include <regex.h>
#include <locale.h>
#include <sys/types.h>
#include <signal.h>
#define BUF 256
#define FOUND 1
#define NOTFOUND 0

sigset_t maskchld;  /* the only SIG I ever want to mask is SIGCHLD, global scope is useful*/

void sigintconfirm_handler(int sig);
int Eval(char *str[], int);
void Pipecommand(char cmdline[]);
void Parallel(char cmdline[]);
int While(char str[]);
int Set(char str[], char str1[], char *);
int Forkcommand();
int Dollar(char *cmdline[]);
int checkExit();
int match(char *string, char *pattern, regex_t *re);
int Calculator();

struct dollarVariable
{
        int value;
        char ID[4];
}dV[10];

int dVcounter;
int main (int argc, char *argv[])
{

    
    
        //initialize signal mask for children
/*        Sigemptyset(&maskchld);
        Sigaddset(&maskchld, SIGCHLD);
        Sigaddset(&maskchld, SIGTSTP);
  */  
        /* Install the signal handlers */

    //    Signal(SIGINT,  sigintconfirm_handler);   /* ctrl-c */

        char* prompt_sign;
        pid_t pid;
        
        /*load PROFILE*/
       // loadprof();
        
        /*login prompt*/
        login();
        
        /*we start in the HOME directory*/
        {
        char* cd;
        //setenv("PWD",getenv("HOME"),1);        
        cd=getenv("HOME");
               
        /*
        int a = chdir(cd);
        
        printf("cd%d: %s",a,cd);
        a = chroot(cd);
        unix_error("oops");
        */
        }
        while(1){
            /*printf("pwd: %s",getenv("PWD"));*/
            char cmdline[100];
            int exitValue=0;
            char * pch,*cmdArray[10];
            /*		char *command[10];*/
            int n=0,i=0;
            char *pattern[] = {"[0-9]+ [+] [0-9]+","[0-9]+ [-] [0-9]+","[0-9]+ [*] [0-9]+","[0-9]+ [/] [0-9]+","[0-9]+ [%] [0-9]+","^Fork","^Set [a-zA-Z0-9]+ [=] [a-zA-Z0-9]*","&$","[a-zA-Z0-9]+ [|]","calc","[e|E][x|X][i|I][T|t]","[$][a-zA-Z]+ [=] [0-9]+"};
            char tempcommand[50];
            int retval,value=0;
            regex_t re;
            char buf[BUF];
            int flag=0;
            int foundFlag=NOTFOUND;
            char c;
    
            prompt_sign = getenv("PROMPT_SIGN");
            prompt_sign = strtok(prompt_sign,"\n");
            
            printf ("\n %s>",prompt_sign);
            gets(cmdline); 

            strcpy(tempcommand,cmdline);
            pch = strtok (cmdline," ");
            cmdArray[n] = pch;
            while (pch != NULL)
            {
                    
                    pch = strtok (NULL, " ");
                    n++;
                    cmdArray[n] = pch;
            }

            for(i = 0;i <12; i++){
                    retval = match(tempcommand, pattern[i], &re);
            if(retval == 0){value=i+1;break;}}

            if((value!=0 && value < 13))
            {
                    switch(value)
                    {
                            case 1: Eval(cmdArray,1);	
                                    break;
                            case 2: Eval(cmdArray,2);
                                    break;
                            case 3: Eval(cmdArray,3);
                                    break;
                            case 4: Eval(cmdArray,4);
                                    break;
                            case 5: Eval(cmdArray,5);
                                    break;
                            case 6: Forkcommand();
                                    break;
                            case 7: Set(cmdArray[1],cmdArray[3],tempcommand);
                                    break;
                            case 8: Parallel(tempcommand);
                                    break;
                            case 9: Pipecommand(tempcommand);
                                    break;
                            case 10: Calculator();
                                    break;
                            case 11: exitValue = checkExit();
                                     if (exitValue==1){return;}
                                     else{break;}
	                    case 12: Dollar(cmdArray);
				     break;
                                            
                    }
                    foundFlag=FOUND;
                    
            }
    
            if(strncmp(tempcommand,"while",5)==0)
            {
                    While(tempcommand);
                    foundFlag=FOUND;
            
            }
    
            else if(foundFlag==NOTFOUND&&cmdArray[0]!=NULL)
            {
                    char temp[50],temp1[50];

                    system("ls /usr/bin > new.txt");
                    strcpy(temp,"grep -s ");
                    strcat(temp,cmdArray[0]);
                    strcat(temp," new.txt");

                    system("ls /bin > new1.txt");
                    strcpy(temp1,"grep -s ");
                    strcat(temp1,cmdArray[0]);
                    strcat(temp1," new1.txt");

            
                    if((system(temp)==0) || (system(temp1)==0))
                    {
                            system(tempcommand);
                            foundFlag=FOUND;
                    }
                    
            }
                            
            if(foundFlag==NOTFOUND)
                    printf("Error: Command '%s' not found",tempcommand);
                        
        }      

}

int match(char *string, char *pattern, regex_t *re)
{
        int status;

        if((status=regcomp( re, pattern, REG_EXTENDED))!= 0)
                return(status);
        status = regexec( re, string, 0, NULL, 0);
        return(status);
}


int Eval( char *cmd[],int operation)
{
        pid_t pid;
        pid = fork();
        if(fork<0)
        {
                perror("fork");
        }
        else
        {
                if(pid==0)
                {
                        float temp;
                        char a[10], b[10];
                        int temp1;
                        float opr1 ;
                        float opr2 ;

                        strcpy(a,cmd[0]);strcpy(b,cmd[2]);
                        opr1 = atof(a);
                        opr2 = atof(b);
                        switch(operation)
                        {
                                case 1: temp = opr1 + opr2;
                                        printf("Ans = %.3f",temp);
                                        break;		
                                case 2: temp = opr1-opr2;
                                        printf("Ans = %.3f",temp);
                                        break;
                                case 3: temp = opr1*opr2;
                                        printf("Ans = %.3f",temp);
                                        break;
                                case 4: temp = opr1/opr2;
                                        printf("Ans = %.3f",temp);
                                        break;
                                case 5: temp1 = (int)opr1 % (int) opr2;
                                        printf("Ans = %d",temp1);
                                        break;
                                default: printf("Invalid Operation");
                                        break;
                        }
                }
                
                else
                {
                        wait();
                }
        }

        printf("\nHint: Type 'calc' for a more sophesticated calculator [Variable Assignements and Integer Expression Evaluation]");
}


int While(char cmdline[])
{
        pid_t pid;
        pid = fork();
        if(fork<0)
        {
                perror("fork");
        }
        else
        {
                if(pid==0)
                {
    
                        char BUFFER[256];
                        char c=0;
                        char temp[256];int n=0,i=0;
                        char *pch;
                        char *token[30];
                        char temp1[5],temp2[5],temp3[5],temp4[5];
                        int errorFlag=0;
			char dollar[5];
			int dVariable;
                        strcpy(temp,cmdline);
                        strcat(temp,"\n");
                        do
                        {
                                gets(BUFFER);	
                                i = strcmp(BUFFER,"done");
                                if (i==0)
                                {c = EOF;}
                                strcat(temp,BUFFER);
                                strcat(temp,"\n");
                        }while(c!=EOF);
                
                        i=0;
                
                        pch = strtok (temp," ,\n");
                        while (pch != NULL)
                        {
                                token[i] = pch;
                                i++;
                                pch = strtok (NULL, " ,\n");
                        }

                        strcpy(temp,token[1]);
                        if (isalpha(temp[3])!=0){
                                printf("\nError: $variable required in Line 1 (with no space in between)");errorFlag=1;}
			
			

			strcpy(dollar,"\0");
			strncat(dollar,temp,3);
			
		
		       for(i=0;i<dVcounter;i++)
		        {
		                if(dollar[2]==dV[i].ID[1])
		                {
                	       		dVariable = dV[i].value; 
					break;
              			 }
			 
		        }

			if(i==dVcounter)
				printf("Error: %s Does Not exist!",dollar);

                        if (strcmp(token[2],"-le")!=0){
                                printf("\nError: Invalid Comparion. '-le' required. in Line 1");errorFlag=1;}

                        strcpy(temp1,token[3]);
                        if (isdigit(temp1[2])!=0){
                                printf("\nError: Integer Value required in Line 1 (with no spaces in betwen)");errorFlag=1;}

                        if (strcmp(token[4],"do")!=0){
                                printf("\nError: Missing 'do' in Line 2");errorFlag=1;}

                        strcpy(temp4,token[9]);
                        if (isalpha(temp4[2])!=0){
                                printf("\n1Error: $variable Required in Line 4 (with no space in between)");errorFlag=1;}

                        if(strcmp(token[10],"=")!=0){
                                printf("\nError: Missing '=' in line 4.");errorFlag=1;}

                        if (strcmp(token[11],"exp")!=0){
                                printf("\nError: Missing 'exp' keyword in Line 4");errorFlag=1;}

                        strcpy(temp2,token[12]);
                        if (isalpha(temp2[3])!=0){
                                printf("\n2Error: $variable required in Line 4 (with no space in between)");errorFlag=1;}
        
                        strcpy(temp3,token[14]);
        /*	int value = atoi(temp3[0]);
        *		if(isdigit()!=0){printf("temp[0] = %c",temp3[0]);
        *				printf("\nError: Integer Value required in Line 4 (with no spaces in between)");errorFlag=1;}*/

                        if(strcmp(token[15],"done")!=0){
                                printf("\nError: Missing 'done' in Line 5");errorFlag=1;}

                        if(errorFlag==0)	
                        {
                                int i=1; /*replace with value of $variable*/
                                char temp [3],tempx [3];
                                int value,value1;
                
                                strncpy(temp,temp1,1);
                                value = atoi(temp);
                		strncpy(tempx,temp3,1);
				value1 = atoi(tempx);
                                while(dVariable < value)
                                {	
                                        char temp[50],temp1[50];
                                        strcpy(temp,"\0");
                                        strcat(temp,token[5]);
                                        strcat(temp," ");
                                        strcat(temp,token[6]);
                                        strcat(temp," ");
                                        strcat(temp,token[7]);
                                        strcat(temp," ");
                                        strcat(temp,token[8]);
                                        printf("\n");
                                        system(temp);
					dVariable = dVariable + value1;
                                }	
                        }
                }
                else
                {
                        wait();
                }
        }

}

int Set(char eVariable[],char eValue[], char *cmdline)
{
        pid_t pid;
        pid = fork();
        if(fork<0)
        {
                perror("fork");
        }
        else
        {
                if(pid==0)
                {
        

                        char temp[10],environVariable[10],environValue[50];
                        
                        strcpy(environVariable,eVariable);
                        strcpy(environValue,eValue);
                        strcpy(temp,getenv(eVariable));		
/*			printf("\n\ntemp=%s,enviironVariable=%s,environValue=%s\n\n",temp,environVariable,environValue);*/

                        /*strcpy(var,'\0');
                        strcat(var,environVariable);
                        strcat(var,"=");
                        strcat(var,environValue);
                        printf("\n\ntemp=%s,evar=%s,eval=%s,var=%s",temp,environVariable,environValue,var);*/
                        if(temp==NULL){
                                        char c;
                                        printf("\n%s is an undefined Environment Variable\n",environVariable);
                                        printf("Create New Environment Variable [y/n] ? ");     
                                        c = getchar(); 
                                        if(c=='y'){
                                                        /*putenv(var)*/;setenv(environVariable,environValue,1);
                                                        printf("Environment Variable '%s' created with value '%s'\n",environVariable,environValue);        
                                                }
                                        }


                        else{
                                char c;
                                printf("Overwrite %s [y/n] ? ",environVariable);
                                c = getchar();
                                if(c=='y'){
                                                /*putenv(var)*/;setenv(environVariable,environValue,1);
                                                printf("Environment Variable '%s' overwritten to '%s'\n",environVariable,environValue);	
                                        }
                                else if (c=='n'){
                                        printf("Environment Variable '%s' remains '%s'\n ",environVariable,getenv(environVariable));
                                                }
                                }
                        }

                        else{wait();}
                
        }

}

int Forkcommand()
{
        pid_t childpid;
        int staus;
        int retval;
        childpid = fork();
        if (childpid < 0) 
        {
                perror("fork");
                
        }
        else
        {
                if(childpid==0)
                        {/*child code */
                        printf("Process Created. PID = %d\n",getpid());
                                
                        }

                else
                        {/*parent code*/
                                wait();
                                
                        } 
        }

}

void Pipecommand(char cmdline[]){}
/*{
printf("%s",cmdline);

        char temp[50];
        char *pch;
        char *cmdArray[10];
        int n=0,i=0;
        strcpy(temp,cmdline);
        pch = strtok (cmdline,"|");
        cmdArray[n] = pch;
        while (pch != NULL)
        {
            printf ("%s;\n",pch);
            pch = strtok (NULL, "|");
            n++;
            cmdArray[n] = pch;
        }*/
        /* cmdArray now has the commands to be piped */
        /* Jeffery's Code Follows */
        /*
        char delims[] = " ";
char ***result;
result=malloc(10*sizeof(char***));

                
        for(i=0;i<n;i++){
                result[i]=malloc(10*sizeof(char**));
                int j=0;
    result[i][j] = strtok( cmdArray[i], delims );	  	  
        while( result[i][j] != NULL ) {
        printf("[%d,%d]=%s  ",i,j,result[i][j]);	
        result[i][++j] = strtok( NULL, delims );  	  
        }
        result[i][j]=0;
        printf("[%d,%d]=%s  \n",i,j,result[i][j]);	
                fflush(stdout);*/
        /*try it out /bin/ls -r | /usr/bin/sort */

/*        }	
        
        fg_piped_create(result, n);
        printf("free");fflush(stdout);
        for(i=0;i<n;i++){
                free(result[i]);
        }	
        free(result);
        
}
*/
void Parallel(char cmdline[]){ }
        /*cmd array contains the command to be run in 'bg'*/
        /* cmdline ends with a '&'*/
        /*jeffer's code*/
        
        /*cmdline pass in the in wrong format, glue code to fix */
/*        char delims[] = " ";
char **result = NULL;
result=malloc(10*sizeof(char*));
result[0] = strtok( cmdline, delims );
        int i=0;
        while( result[i++] != NULL ) {
    result[i] = strtok( NULL, delims );
}
        result[i-2]=NULL; //overwrite the & sign
        printf("runin background %s \n",result[0]);
        fflush(stdout);
        bg_create(result);
        free(result);
}
*/
int Calculator()
{
        int ret;
        pid_t calcpid;
        calcpid = fork();
        
        if(calcpid>=0)
        {
                if(calcpid==0)
                {
                        
                        printf("\nCalculator [Do Not give spaces between values]\n(Enter 'exit' to return)\n");
                                execvp("/home/rishabh_romit/source/calculator",NULL);
                                
                                
                }
                else
                {
                        wait();
                }
        }
        else
        {
                perror("fork");
        }
}

int checkExit()
{
        
    char c='\0';
    printf("Are you sure [yY/nN] ?");
    c = getchar();
    if ( c=='y' || c=='Y')
    {
            return(1);	
            
    }
    return 0;        

}
/* 
* sigint_handler - The kernel sends a SIGINT to the shell whenver the
*    user types ctrl-c at the keyboard.  Catch it and send it along
*    to the foreground job.  
*/
void sigintconfirm_handler(int sig)  
{       
    printf("\nDo you want to exit??? (y/n)");
    char answer[100];
    gets(answer);
    if(answer[0]=='y')
        exit(0);

    return;
}

int Dollar(char *cmdArray[])
{
	char c,val[5],dollar[5];
	int temp,i,found=0;
	
	
	for(i=0;i<dVcounter;i++)
	{
		if(strcmp(cmdArray[0],dV[i].ID)==0)
		{
			printf("\n%s = %d exists!",dV[i].ID,dV[i].value);
			found = 1;
			return;
		}
	}		
			
	if(dVcounter==10 && found==0)
	{
		printf("Maximum $Variables created. Free Previous [y/n]?");
		c=getchar();
		if(c=='y')
		{
			dVcounter=0;
			for(i=0;i<10;i++)
			{
				dV[i].value = 0;
				strcpy(dV[i].ID,"NULL");
			}
		}
	}
	if(dVcounter < 10 && found==0)
	{
		strcpy(val,cmdArray[2]);	
		strcpy(dollar,cmdArray[0]);
				
		dV[dVcounter].value = atoi(val);
		strcpy(dV[dVcounter].ID,dollar);
		temp = dVcounter;	
		dVcounter+=1;

	}
	printf("\n%s = %d\n",dV[temp].ID,dV[temp].value);

}
	
	
